#include "atom.h"
#define ATOM_NONE_STANDARDIO
#include "dfs.h"
#include "debug.h"
#include "syslog.h"
#include "console.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include "numberical.h"

static enConsoleResult ls_cmd(int argc, char *argv[]) {
    const char *path = (argc > 1) ? argv[1] : "."; // 如果提供了路径，则使用它，否则使用当前目录
    DIR *dir = opendir(path);

    if (!dir) {
        SYSLOG(LOG_ERR, "%s", strerror(errno));
        return CE_OK;
    }

    struct dirent *entry;
    struct stat fileStat;
    static char fullpath[256];
    while ((entry = readdir(dir)) != NULL) {
        // 获取文件信息
        l_vsnprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name);
        if (stat(fullpath, &fileStat) == 0) {
            char timeBuf[64];
            struct tm *timeinfo;

            // 格式化时间
            timeinfo = localtime(&fileStat.st_mtime);
            strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", timeinfo);

            // 根据文件类型打印信息
            if (entry->d_type == DT_DIR) {
                KPrintf("%-30s %-6s\r\n", 
                        entry->d_name, 
                        "<DIR>");
            } else {
                KPrintf("%-30s %8d bytes %s\r\n", 
                        entry->d_name, 
                        fileStat.st_size,
                        timeBuf);
            }
        }
    }

    closedir(dir);
    return CE_OK;
}

// cp: 复制文件
static enConsoleResult cp_cmd(int argc, char *argv[]) {
    if (argc != 3) {
        KPrintf("Usage: cp <source> <destination>\r\n");
        return CE_PARAM_ERROR;
    }

    FILE *src = fopen(argv[1], "rb");

    if (!src) {
        SYSLOG(LOG_ERR, "%s", strerror(errno));
        return CE_OK;
    }

    FILE *dest = fopen(argv[2], "wb");
    if (!dest) {
        SYSLOG(LOG_ERR, "%s", strerror(errno));
        fclose(src);
        return CE_OK;
    }

    static char buffer[4096];
    size_t bytes;
    while ((bytes = fread(buffer, 1, sizeof(buffer), src)) > 0) {
        fwrite(buffer, 1, bytes, dest);
    }

    fclose(src);
    fclose(dest);
    return CE_OK;
}

// pwd: 打印当前工作目录
static enConsoleResult pwd_cmd(int argc, char *argv[]) {
    static char cwd[128];
    if (getcwd(cwd, sizeof(cwd)) != NULL) {
        KPrintf("%s\r\n", cwd);
    } else {
        SYSLOG(LOG_ERR, "%s", strerror(errno));
    }

    return CE_OK;
}

// cd: 切换目录
static enConsoleResult cd_cmd(int argc, char *argv[]) {
    if (argc != 2) {
        KPrint("Usage: cd <directory>\r\n");
        return CE_PARAM_ERROR;
    }

    if (chdir(argv[1]) != 0) {
        SYSLOG(LOG_ERR, "%s", strerror(errno));
    }

    return CE_OK;
}

// del: 删除文件
static enConsoleResult del_cmd(int argc, char *argv[]) {
    if (argc != 2) {
        KPrint("Usage: del <file>\r\n");
        return CE_PARAM_ERROR;
    }

    if (unlink(argv[1]) != 0) {
        SYSLOG(LOG_ERR, "%s", strerror(errno));
    }

    return CE_OK;
}

// ren: 重命名文件
static enConsoleResult ren_cmd(int argc, char *argv[]) {
    if (argc != 3) {
        KPrintf("Usage: ren <old_name> <new_name>\r\n");
        return CE_PARAM_ERROR;
    }

    if (rename(argv[1], argv[2]) != 0) {
        SYSLOG(LOG_ERR, "%s", strerror(errno));
    }

    return CE_OK;
}

// mkdir: 创建目录
static enConsoleResult mkdir_cmd(int argc, char *argv[]) {
    if (argc != 2) {
        KPrint("Usage: mkdir <directory>\r\n");
        return CE_PARAM_ERROR;
    }

    if (mkdir(argv[1], 0755) != 0) {
        SYSLOG(LOG_ERR, "%s", strerror(errno));
    }

    return CE_OK;
}

// rmdir: 删除空目录
static enConsoleResult rmdir_cmd(int argc, char *argv[]) {
    if (argc != 2) {
        KPrintf("Usage: rmdir <directory>\r\n");
        return CE_PARAM_ERROR;
    }

    if (rmdir(argv[1]) != 0) {
        SYSLOG(LOG_ERR, "%s", strerror(errno));
    }

    return CE_OK;
}

static enConsoleResult touch_cmd(int argc, char *argv[]) {
    if (argc < 2) {
        SYSLOG(LOG_ERR, "Missing file name argument");
        return CE_PARAM_ERROR;
    }

    FILE *f = fopen(argv[1], "w");
    if (f == NULL)
    {
        SYSLOG(LOG_ERR, "Failed to open file for writing");
        return CE_RUNTIME_ERROR;
    }

    fclose(f);
    SYSLOG(LOG_INFO, "File written");

    return CE_OK;
}


static enConsoleResult type_cmd(int argc, char *argv[]) {
    if (argc < 3) {
        SYSLOG(LOG_ERR, "Usage: type <file_name> <content>");
        return CE_PARAM_ERROR;
    }

    // Open the file for writing.
    FILE *f = fopen(argv[1], "w");
    if (f == NULL) {
        SYSLOG(LOG_ERR, "Failed to open file for writing");
        return CE_RUNTIME_ERROR;
    }

    // Write the content to the file.
    for (int i = 2; i < argc; i++) {
        if (fprintf(f, "%s", argv[i]) < 0) {
            SYSLOG(LOG_ERR, "Failed to write to file");
            fclose(f);
            return CE_OK;
        }
        // Add a space between arguments, but not after the last one.
        if (i < argc - 1) {
            if (fprintf(f, " ") < 0) {
                SYSLOG(LOG_ERR, "Failed to write to file");
                fclose(f);
                return CE_OK;
            }
        }
    }
    fprintf(f, "\n"); // Add a newline at the end for better formatting.
    fclose(f);

    SYSLOG(LOG_INFO, "File written successfully: %s", argv[1]);

    return CE_OK;
}

static enConsoleResult cat_cmd(int argc, char *argv[]) {
    if (argc < 2) {
        SYSLOG(LOG_ERR, "cat [file]");
        return CE_PARAM_ERROR;
    }

    FILE *f = fopen(argv[1], "r");
    if (f == NULL)
    {
        SYSLOG(LOG_ERR, "Failed to open file for read");
        return CE_RUNTIME_ERROR;
    }
       // Read and display the file's content.
    char buffer[64]; // Buffer for reading file content.
    while (fgets(buffer, sizeof(buffer), f) != NULL) {
        KPrint(buffer); // Output file content to console.
    }

    fclose(f);

    return CE_OK;
}


#ifdef COM_USE_CONSOLE
BGEIN_DEF_CMD(_cmds)
    CMD_DEF_ALISA(ls, ls_cmd, "list folder files")
    CMD_DEF_ALISA(cp, cp_cmd, "copy file")
    CMD_DEF_ALISA(pwd, pwd_cmd, "show current path")
    CMD_DEF_ALISA(cd, cd_cmd, "enter path")
    CMD_DEF_ALISA(del, del_cmd, "del file")
    CMD_DEF_ALISA(ren, ren_cmd, "rename file")
    CMD_DEF_ALISA(mkdir, mkdir_cmd, "make path")
    CMD_DEF_ALISA(rmdir, rmdir_cmd, "remove path")
    CMD_DEF_ALISA(touch, touch_cmd, "touch file")
    CMD_DEF_ALISA(cat, cat_cmd, "cat file")
    CMD_DEF_ALISA(type, type_cmd, "type file content")
END_DEF_CMD()

#endif  /* COM_USE_CONSOLE && COM_USE_SHELL_CMD*/

int  DfsDeviceIoCtl(DfsDevice *dev, int function, void *arg)
{
    if( dev->Protected.ops != NULL){
        return dev->Protected.ops->ioctl( dev, function, arg);
    }

    return ATOM_ERROR;
}

void DfsDeviceCreate(DfsDevice *dev, const char *mount_point, const DeviceDesc *desc, DfsOps *ops)
{
    dev->Protected.mount_point = mount_point;
    dev->Protected.ops = ops;
    DeviceInstall(&dev->super, desc);    

#ifdef COM_USE_CONSOLE
	CONSOLE_REG_CMD(_cmds);
#endif

    SYSLOG(LOG_INFO, "device %s initlized", desc->name);
}
